package com.bridgeintelligent.tag.webserver.security;

import com.bridgeintelligent.tag.constants.ExceptionCodes;
import com.bridgeintelligent.tag.constants.TagConstants;
import com.bridgeintelligent.tag.user.mgmt.pojo.User;
import com.bridgeintelligent.tag.user.query.service.UserQueryService;
import com.bridgeintelligent.tag.utils.SecurityHelper;
import com.bridgeintelligent.tag.webserver.security.aes.AesUtils;
import com.bridgeintelligent.tag.webserver.security.session.UserSessionManager;
import com.wayneleo.quickstart.framework.BaseResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.UUID;

@Api(tags = "认证相关接口")
@RestController("Web-DefaultAuthenticationController")
@RequestMapping("/api/security")
@AllArgsConstructor
@Slf4j
public class DefaultAuthenticationController {
    private ShiroConfiguration configuration;
    private UserQueryService userQueryService;
    private static LocalCache localCache;
    private static final String CCIS_LW_PWD;
    private TagSessionMapper sessionMapper;

    static {
        localCache = new LocalCache();
        CCIS_LW_PWD = "@ThirdPartIn#";
    }

    @ApiOperation(value = "页面登录", notes = "code:0为成功，code:非0为失败")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "username", value = "用户名", required = true),
            @ApiImplicitParam(paramType = "query", name = "password", value = "密码", required = true),
    })
    @PostMapping("/login")
    public LoginResponse login(String username, String password,HttpServletResponse servletResponse) {

        try {
            username = AesUtils.aesDecrypt(username, AesUtils.AES_KEY);
            password = AesUtils.aesDecrypt(password, AesUtils.AES_KEY);
            log.info("解密后的用户名：{}，密码：{}",username,password);
        } catch (Exception e) {
            log.info("解密失败",e);
            LoginResponse response = new LoginResponse();
            response.setCode(-1);
            response.setMsg("解密失败");
            return response;
        }

        TagRealm.Token token = new TagRealm.Token(username, password);

        //先判断本地缓存里有没有当前用户的登陆信息
        Object object = localCache.get(username);
        if (object != null){
            if ((int)object > 3){
                throw new AuthenticationException(ExceptionCodes.SECURITY_50007);
            }
        }
        try{
            //获取session数据
            Session session = SecurityUtils.getSubject().getSession();
            UserSessionManager.newInstance().removeSession(null, session.getId().toString());
            final LinkedHashMap<Object, Object> attributes = new LinkedHashMap<Object, Object>();
            final Collection<Object> keys = session.getAttributeKeys();
            for (Object key : keys) {
                final Object value = session.getAttribute(key);
                if (value != null)
                { attributes.put(key, value); }
            }
            session.stop();

            // 登录成功后复制session数据
            session = SecurityUtils.getSubject().getSession();
            for (final Object key : attributes.keySet())
            { session.setAttribute(key, attributes.get(key)); }
            TagSecurityHelper.login(token);

            localCache.remove(username);
            addCookie(username,servletResponse);
        }catch (Exception exception){
            if (object == null){
                localCache.set(username,1,1000*60);
            }else{
                localCache.set(username,(int)object+1,1000*60);
            }
            sessionMapper.delete(SecurityHelper.shiroSession().getId().toString());
            throw new AuthenticationException(ExceptionCodes.SECURITY_50004);
        }
        return new LoginResponse(new LoginResponse.Data(TagSecurityHelper.currentUser(),
                TagSecurityHelper.currentPermissions()));
    }

    @ApiOperation(value = "退出登录", notes = "code:0为成功，code:非0为失败")
    @GetMapping("/logout")
    public BaseResponse logout() {
        User currentUser = (User) SecurityHelper.shiroSession().getAttribute(TagConstants.SESSION_KEY_OF_USER);
        UserSessionManager.newInstance().removeSession(currentUser.getUserId(), null);
        TagSecurityHelper.logout();
        BaseResponse resp = new BaseResponse();
        resp.setCode(0);
        return resp;
    }

    @ApiOperation(value = "拉取当前用户信息", notes = "没登录将返回游客身份")
    @GetMapping("/user")
    public LoginResponse user() {
        User user = TagSecurityHelper.currentUser();
        Set<String> permissions = TagSecurityHelper.currentPermissions();
        if (user == null || SecurityHelper.isGuestUsername(user.getUsername())) {
            throw new AuthenticationException(ExceptionCodes.SECURITY_50003);
        }
        return new LoginResponse(new LoginResponse.Data(user, permissions));
    }

    @ApiOperation(value = "拉取系统安全类信息", notes = "例如登录地址等")
    @GetMapping("/info")
    public TagSecurityInfo info() {
        TagSecurityInfo info = new TagSecurityInfo().setData(new TagSecurityInfo.Data(
                configuration.LOGIN_URL,
                configuration.LOGOUT_URL));
        info.setCode(0);
        return info;
    }

    @ApiOperation(value = "三方接入接口1", notes = "返回uuid")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "loginName", value = "用户名", required = true)
    })
    @PostMapping("/tag/synLoginUUID")
    public AccessResponse ccisCheck(String loginName) {
        log.info("-------三方接入接口1------------登陆名："+loginName);
        AccessResponse resp = new AccessResponse();
        User user = userQueryService.findOneByUsername(loginName);
        if (user == null) {
            log.info("-------三方接入接口1------------user信息为null");
            resp.setMsg("用户不存在");
        } else {
            resp.setCode(0);
            String synLoginUUID = UUID.randomUUID().toString()
                    .replaceAll("-", "");
            log.info("三方接入接口1------------登陆用户："+loginName+"--------返回UUID："+synLoginUUID);
            resp.setSynLoginUUID(synLoginUUID);
            localCache.set(synLoginUUID, loginName, 1000 * 30);
            resp.setMsg("用户存在,返回synLoginUUID");
        }
        return resp;
    }

    @ApiOperation(value = "三方接入接口2", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "synLoginUUID", value = "uuid", required = true)
    })
    @GetMapping("/tag/logins")
    public void ccisLogin(String synLoginUUID, HttpServletRequest req, HttpServletResponse resp) {
        log.info("----------三方接入接口2------------参数UUID:"+synLoginUUID);
        try {
            resp.setHeader("Access-Control-Allow-Origin", "*");
            resp.sendRedirect(req.getContextPath()
                    + "/index.html/#/login?synLoginUUID=" + synLoginUUID);
            log.info("---------三方接入接口2--------返回url:"+req.getContextPath() + "/index.html/#/login?synLoginUUID=" + synLoginUUID);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @ApiOperation(value = "三方接入接口3", notes = "")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", name = "synLoginUUID", value = "uuid", required = true)
    })
    @PostMapping("/web/login")
    public LoginResponse webLogin(String synLoginUUID,HttpServletResponse servletResponse) {
        log.info("----------三方接入接口3------------参数UUID:"+synLoginUUID);
        AccessResponse resp = new AccessResponse();
        Object value = localCache.get(synLoginUUID);
        if (value == null) {
            resp.setMsg("token过期");
            resp.setCode(999);
            log.info("-------------------三方接入接口3-------token过期");
            return resp;
        } else {
            TagRealm.Token token = new TagRealm.Token(String.valueOf(value), CCIS_LW_PWD);
            TagSecurityHelper.login(token);
            addCookie(String.valueOf(value),servletResponse);
            return new LoginResponse(new LoginResponse.Data(TagSecurityHelper.currentUser(),
                    TagSecurityHelper.currentPermissions()));
        }
    }

    public void addCookie(String username,HttpServletResponse response) {
        try {
            Cookie cookie = new Cookie("iss_useracct",AesUtils.aesEncrypt(username,AesUtils.JS_KEY));
            cookie.setPath("/");
            cookie.setMaxAge(-1);
            cookie.setHttpOnly(false);
            cookie.setSecure(false);
            response.addCookie(cookie);
        }catch (Exception e){
            log.warn("AES加密出错！"+e.getMessage());
        }

    }

}
